﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO.Ports;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Windows.Threading;

namespace yunyistars_serial_port_tool
{
    public partial class SerialPortToolWin : Form
    {
        #region 变量
        /// <summary>
        /// 委托-用作响应模式
        /// </summary>
        /// <param name="text"></param>
        public delegate void showReceiveDelegate(string text);

        /// <summary>
        /// 串口对象
        /// </summary>

        SerialPort _com = new SerialPort();

        #endregion 变量

        public SerialPortToolWin()
        {
            InitializeComponent();
        }

        private void SerialPortToolWin_Load(object sender, EventArgs e)
        {
            try
            {
                // 获取本机所有串口的名字
                string[] strportName = SerialPort.GetPortNames();
                cmbPort.Items.Clear();
                cmbPort.DataSource = strportName;
                if (strportName.Length > 0) { cmbPort.SelectedIndex = 0; }

                // 波特率
                cmbBaudRate.SelectedIndex = 0;
                // 数据位
                cmbDataBits.SelectedIndex = 0;
                // 停止位
                cmbStopBits.SelectedIndex = 0;
                // 校验位
                cmbParityCheck.SelectedIndex = 0;
                // 流控制
                cmbHandshake.SelectedIndex = 0;
            }
            catch (Exception ex)
            {
                MessageBox.Show("云逸星空串口助手初始化出错！错误信息：" + ex.Message, "初始化异常", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }

        /// <summary>
        /// 刷新端口
        /// </summary>
        private void btnRefreshPort_Click(object sender, EventArgs e)
        {
            // 获取本机所有串口的名字
            string[] strportName = SerialPort.GetPortNames();
            cmbPort.DataSource = strportName;
            if (strportName.Length > 0) { cmbPort.SelectedIndex = 0; }
        }

        /// <summary>
        /// 打开/关闭串口
        /// </summary>
        private void btnOpen_Click(object sender, EventArgs e)
        {
            try
            {
                if (_com.IsOpen)
                {
                    _com.Close();  // 关闭接口
                }  // 关闭
                else
                {
                    _com.ReadTimeout = 3000;    // 超时限制
                    _com.WriteTimeout = 3000;  // 超时限制
                    _com.PortName = cmbPort.Text;                 // 串口号
                    _com.BaudRate = int.Parse(cmbBaudRate.Text);  // 波特率
                    _com.DataBits = int.Parse(cmbDataBits.Text);  // 数据位

                    // 停止位
                    switch (cmbStopBits.Text.Trim())
                    {
                        case "1位":
                            _com.StopBits = StopBits.One;  // 使用一个停止位
                            break;
                        case "1.5位":
                            _com.StopBits = StopBits.OnePointFive;  // 使用两个停止位
                            break;
                        case "2位":
                            _com.StopBits = StopBits.Two;  // 使用两个停止位
                            break;
                        default:
                            _com.StopBits = StopBits.One;  // 不使用停止位
                            break;
                    }

                    // 奇偶校验
                    switch (cmbParityCheck.Text.Trim())
                    {
                        case "无校验":
                            _com.Parity = Parity.None;   // 不检查
                            break;
                        case "奇校验":
                            _com.Parity = Parity.Odd;    // 位数等于奇数
                            break;
                        case "偶校验":
                            _com.Parity = Parity.Even;   // 位数等于偶数
                            break;
                        case "置1":
                            _com.Parity = Parity.Mark;   // 奇偶校验位保留为1
                            break;
                        case "置0":
                            _com.Parity = Parity.Space;  // 奇偶校验位保留为0
                            break;
                        default:
                            _com.Parity = Parity.None;   // 不检查
                            break;
                    }

                    // 流控制
                    switch (cmbHandshake.Text.Trim())
                    {
                        case "不控制":
                            _com.Handshake = Handshake.None;                  // 不控制
                            break;
                        case "XOn/XOff":
                            _com.Handshake = Handshake.XOnXOff;               // 使用XOn/XOff控制
                            break;
                        case "RTX":
                            _com.Handshake = Handshake.RequestToSend;         // 使用RTX控制
                            break;
                        case "RTX+XOn/XOff":
                            _com.Handshake = Handshake.RequestToSendXOnXOff;  // 使用RTX控制+XOn/XOff控制
                            break;
                        default:
                            _com.Handshake = Handshake.None;                  // 不控制
                            break;
                    }

                    _com.Open();  // 打开接口
                }  // 打开
            }
            catch (Exception ex)
            {
                txtStatus.Text += "\r\n串口打开错误或串口不存在！";  // 出错提示
            }

            // 改变颜色
            if (_com.IsOpen)
            {
                // 颜色指示
                btnOpen.Text = "关闭串口";
                btnOpen.BackColor = Color.FromArgb(128, 255, 128);
                txtStatus.Text += "\r\n串口已打开！";  // 记录
                btnSend.Enabled = true;  // 启用发送按钮
                if (rbAck.Checked) btnReceive.Enabled = true;  // 启动接收按钮
            }
            else
            {
                // 颜色指示
                btnOpen.Text = "打开串口";
                btnOpen.BackColor = Color.FromArgb(255, 128, 128);
                txtStatus.Text += "\r\n串口已关闭！";  // 记录
                btnSend.Enabled = false;  // 关闭发送按钮
                if (rbAck.Checked) btnReceive.Enabled = false;  // 关闭接收按钮
            }
        }

        /// <summary>
        /// 发送
        /// </summary>
        private async void btnSend_Click(object sender, EventArgs e)
        {
            try
            {
                byte[] data = null;  // 发送的数据

                bool isChkSendHex = false;
                this.Invoke(new Action(() =>
                {
                    isChkSendHex = chkSendHex.Checked;
                }));
                if (isChkSendHex)  // 是否为十六进制发送
                {
                    data = GetBytesFromString(txtSendMsg.Text.Trim());  // 转十六进制
                }
                else
                {
                    data = Encoding.Default.GetBytes(txtSendMsg.Text.Trim());  // 普通数据
                }
                _com.Write(data, 0, data.Length);

                this.Invoke(new Action(() =>
                {
                    txtStatus.Text += "\r\n发送成功！数据为：" + txtSendMsg.Text.Trim();
                }));
            }
            catch (Exception ex)
            {
                this.Invoke(new Action(() =>
                {
                    txtStatus.Text += "\r\n发送出错！错误信息：" + ex.Message;
                }));
            }
        }

        /// <summary>
        /// 接收（应答模式可用）
        /// </summary>
        private void btnReceive_Click(object sender, EventArgs e)
        {
            try
            {
                int count = _com.BytesToRead;        // 获取读取缓存中的缓存大小
                byte[] readBuffer = new byte[count];  // 内容对象
                _com.Read(readBuffer, 0, count);      // 获取内容

                string ss = string.Empty;  // 

                if (chkRecHex.Checked)
                {
                    ss = GetStringFromBytes(readBuffer);  // 转十六进制
                    txtReceive.Text = ss;  // 转十六进制
                }
                else
                {
                    ss = Encoding.Default.GetString(readBuffer);  // 普通数据
                    txtReceive.Text = ss;  // 普通数据
                }

                txtStatus.Text += "\r\n接收成功！数据为：" + ss;
            }
            catch (Exception ex)
            {
                txtStatus.Text += "\r\n接收出错！错误信息：" + ex.Message;
            }
        }

        /// <summary>
        /// 选择“响应模式”
        /// </summary>
        private void rbResponse_CheckedChanged(object sender, EventArgs e)
        {
            try
            {
                _com.DataReceived += new SerialDataReceivedEventHandler(Com_DataReceived);  // 设置接收事件
            }
            catch (Exception ex)
            {
                txtStatus.Text += "\r\n选择“响应模式”出错！错误信息：" + ex.Message;
            }
        }

        /// <summary>
        /// 选择“应答模式”
        /// </summary>
        private void rbAck_CheckedChanged(object sender, EventArgs e)
        {
            try
            {
                _com.DataReceived -= new SerialDataReceivedEventHandler(Com_DataReceived);  // 移除接收事件
            }
            catch (Exception ex)
            {
                txtStatus.Text += "\r\n选择“应答模式”出错！错误信息：" + ex.Message;
            }
        }

        /// <summary>
        /// 消息自动接收事件
        /// </summary>
        /// <exception cref="NotImplementedException"></exception>
        private void Com_DataReceived(object sender, SerialDataReceivedEventArgs e)
        {
            try
            {
                bool isRecHex = false;  // 是否以十六进制显示

                this.Invoke(new Action(() =>
                {
                    isRecHex = chkRecHex.Checked;
                }));

                int count = _com.BytesToRead;        // 获取读取缓存中的缓存大小
                byte[] readBuffer = new byte[count];  // 内容对象
                _com.Read(readBuffer, 0, count);      // 获取内容

                string strReceive = string.Empty;
                if (isRecHex)  // 使用十六进制
                {
                    strReceive = GetStringFromBytes(readBuffer);
                }
                else
                {
                    strReceive = Encoding.Default.GetString(readBuffer);
                }

                this.Invoke(new Action(() =>
                {
                    txtReceive.Text = strReceive;
                    txtStatus.Text += "\r\n接收成功！数据为：" + strReceive;
                }));

            }
            catch (Exception ex)
            {
                this.Invoke(new Action(() =>
                {
                    txtStatus.Text += "\r\n响应模式运行出错！错误信息：" + ex.Message;
                }));
            }
        }

        #region 方法

        /// <summary>
        /// “十六进制字符串”转化为“字节数组”
        /// </summary>
        /// <param name="pString"></param>
        /// <returns></returns>
        public byte[] GetBytesFromString(string pString)
        {
            string[] str = pString.Split(' ');
            byte[] bytes = new byte[str.Length];

            for (int i = 0; i < str.Length; i++)
            {
                bytes[i] = Convert.ToByte(Convert.ToInt32(str[i], 16));
            }
            return bytes;  // 返回数组
        }

        /// <summary>
        /// “字节数组”转化为“十六进制字符串”
        /// </summary>
        /// <param name="pByte"></param>
        /// <returns></returns>
        public string GetStringFromBytes(byte[] pByte)
        {
            string str = string.Empty;

            for (int i = 0; i < pByte.Length; i++)
            {
                str += (pByte[i].ToString("X").PadLeft(2, '0') + " ");
            }
            str = str.TrimEnd(' ');  // 删除末尾的空格
            return str;
        }
        #endregion 方法

        /// <summary>
        /// 状态信息框保持在最后一行
        /// </summary>
        private void txtStatus_TextChanged(object sender, EventArgs e)
        {
            this.txtStatus.SelectionStart = this.txtStatus.Text.Length;
            this.txtStatus.SelectionLength = 0;
            this.txtStatus.ScrollToCaret();
        }
    }
}